#pragma once

#include <iostream>
#include <string>
#include <functional>
#include <cstring>
#include <cstdlib>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "err.hpp"

const int MSG_BUF_SIZE = 1024;
using serv_func_t = std::function<std::string(const std::string &str)>;

// 接收客户端的信息，并传回客户端
// plus: 服务端对客户端发来的信息做业务处理后再发回

class UdpServer
{
public:
    UdpServer(int port, serv_func_t service) : _port(port), _service(service)
    {
    }

    void Initial()
    {
        // 1. 创建socket套接字（协议族，声明是哪种通信、哪种协议）
        int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
        if (sockfd < 0)
        {
            // 创建套接字失败
            std::cerr << strerror(errno) << std::endl;
            exit(SOCKET_ERR);
        }
        _sockfd = sockfd;

        std::cout << "socket creat success: " << _sockfd << std::endl;

        // 2. 绑定特定的IP地址和端口号（地址族，标定网络通信地址）
        struct sockaddr_in sin;
        bzero(&sin, sizeof(sin));

        sin.sin_family = AF_INET;
        sin.sin_port = htons(_port);

        // sin.sin_addr.s_addr = inet_addr(_ip.c_str());
        // in_addr_t inet_addr(const char *cp);
        // 将点分字符串形式的ip地址转成四字节整数形式
        // 并且从主机字节序转换为网络字节序

        // 云服务器可能有多个ip地址，无法指定一个，用INADDR_ANY表示该服务器的任意ip
        // 表示只要发到该服务器上的信息都可以接收
        sin.sin_addr.s_addr = INADDR_ANY;

        if (bind(_sockfd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
        {
            // 绑定失败
            std::cerr << strerror(errno) << std::endl;
            exit(BIND_ERR);
        }

        std::cout << "socket bind success: "
                  << "port->" << _port << std::endl;
    }

    void Start()
    {
        while (true)
        {
            // 1. 数据接收
            char msg_buf[MSG_BUF_SIZE];
            memset(msg_buf, 0, MSG_BUF_SIZE);

            struct sockaddr_in cln;
            bzero(&cln,sizeof(cln));
            socklen_t len;

            ssize_t rn = recvfrom(_sockfd, msg_buf, sizeof(msg_buf) - 1, 0, (struct sockaddr *)&cln, &len);
            if (rn < 0)
            {
                // 接收失败
                std::cerr << strerror(errno) << std::endl;
                exit(RECV_ERR);
            }
            msg_buf[rn] = '\0';

            // 2. 业务处理
            std::cout << "[" << inet_ntoa(cln.sin_addr) << ":" << ntohs(cln.sin_port) << "] ";
            std::cout << "#用户输入指令# " << msg_buf << std::endl;
            std::string respond = _service(msg_buf);

            

            // 3. 数据传回客户端

            ssize_t sn = sendto(_sockfd, respond.c_str(), respond.size(), 0, (struct sockaddr *)&cln, sizeof(cln));
            if (sn < 0)
            {
                std::cerr << errno << " " << strerror(errno) << std::endl;
                exit(SEND_ERR);
            }
        }
    }

private:
    int _sockfd;
    uint16_t _port;
    serv_func_t _service;
};
